function! api#async#init() abort
    call s:asynctasks()
    call s:asyncomplete()
endfunction

function! api#async#run() abort
    return s:asyncrun()
endfunction

function! api#async#tasks() abort
    return s:asynctasks()
endfunction

function! s:asyncrun() abort
    if !exists("g:asyncrun_exit")
        try
            packadd asyncrun.vim
        catch /.*/
            echoerr v:exception
        endtry
    endif
    if exists("g:asyncrun_exit")
        let g:asyncrun_open = 0
        let g:asyncrun_rootmarks = ['.git', '.svn', '.root', '.project', '.hg']
        return v:true
    endif
    return v:false
endfunction

function! s:quickui() abort
    if !exists('g:quickui_version')
        try
            packadd vim-quickui
        catch /.*/
            echoerr v:exception
        endtry        
    endif 
    if exists("g:quickui_version") && g:quickui_version
    endif 
endfunction

function! s:asynctasks() abort
    if !exists('g:asynctasks_system')
        try
            packadd asynctasks.vim
        catch /.*/
            echoerr v:exception
        endtry
    endif
    if exists('g:asynctasks_system') && s:asyncrun()
        let g:asynctasks_config_name = '.asynctask'
        let g:asynctasks_rtp_config = "asynctasks.ini"
        let g:asynctasks_extra_config = [
                    \ '~/.config/asynctasks/asynctasks.ini',
                    \ ]
        let g:asynctasks_term_pos = "quickui"
        let g:asynctasks_term_rows = 10
        let g:asynctasks_term_cols = 80
        let g:asynctasks_term_reuse = 1
        let g:asynctasks_term_hidden = 0
        let g:asynctasks_term_listed = 1
        let g:asynctasks_confirm = 1
        let g:asynctasks_template = {}
        let g:asynctasks_template.cargo = [
                    \ "[project-init]",
                    \ "command=cargo update",
                    \ "cwd=<root>",
                    \ "",
                    \ "[project-build]",
                    \ "command=cargo build",
                    \ "cwd=<root>",
                    \ "errorformat=%. %#--> %f:%l:%c",
                    \ "",
                    \ "[project-run]",
                    \ "command=cargo run",
                    \ "cwd=<root>",
                    \ "output=terminal",
                    \ ]

        noremap <silent><f5> :AsyncTask file-run<cr>
        noremap <silent><f9> :AsyncTask file-build<cr>
        noremap <silent><f6> :AsyncTask project-run<cr>
        noremap <silent><f7> :AsyncTask project-build<cr>
        let g:asynctasks_keymap = get(g:, "asynctasks_keymap", { "name": "+asynctasks" })
        let g:asynctasks_keymap.e = [":AsyncTaskEdit", "编辑本地任务"]
        let g:asynctasks_keymap.E = [":AsyncTaskEdit!", "编辑全局任务"]
        let g:asynctasks_keymap.l = [":AsyncTaskList", "查看除以点`.`开头的任务"]
        let g:asynctasks_keymap.L = [":AsyncTaskList!", "查看所有任务"]
        let g:async_keymap = get(g:, "async_keymap", { "name" : "+async" })
        let g:async_keymap.t = g:asynctasks_keymap 
        let g:space_keymap = get(g:, "space_keymap", { "name" : "+space" })
        let g:space_keymap.a = g:async_keymap 
        return v:true
    endif
    return v:false
endfunction

" Below example implements removing duplicates.
function! s:my_asyncomplete_preprocessor(options, matches) abort
    let l:visited = {}
    let l:items = []
    for [l:source_name, l:matches] in items(a:matches)
        for l:item in l:matches['items']
            if stridx(l:item['word'], a:options['base']) == 0
                if !has_key(l:visited, l:item['word'])
                    call add(l:items, l:item)
                    let l:visited[l:item['word']] = 1
                endif
            endif
        endfor
    endfor
    call asyncomplete#preprocess_complete(a:options, l:items)
endfunction

" Below example implements a priority sort function.
function! s:sort_by_priority_preprocessor(options, matches) abort
    let l:items = []
    for [l:source_name, l:matches] in items(a:matches)
        for l:item in l:matches['items']
            if stridx(l:item['word'], a:options['base']) == 0
                let l:item['priority'] =
                            \ get(asyncomplete#get_source_info(l:source_name),'priority',0)
                call add(l:items, l:item)
            endif
        endfor
    endfor
    let l:items = sort(l:items, {a, b -> b['priority'] - a['priority']})
    call asyncomplete#preprocess_complete(a:options, l:items)
endfunction

function! s:asyncomplete() abort
    if !exists("g:asyncomplete_loaded")
        try
            packadd asyncomplete.vim
        catch /.*/
            echoerr v:exception
        endtry
    endif
    if exists("g:asyncomplete_loaded") && g:asyncomplete_loaded
        let g:asyncomplete_enable_for_all = 1
        let g:asyncomplete_auto_popup = 1
        let g:asyncomplete_popup_delay = 30
        " let g:asyncomplete_preprocessor = []
        let g:asyncomplete_preprocessor = [
                    \ function('s:my_asyncomplete_preprocessor'),
                    \ function('s:sort_by_priority_preprocessor')
                    \ ]
        let g:asyncomplete_min_chars = 0
        let g:asyncomplete_matchfuzzy = exists("*matchfuzzypos")
        set shortmess+=c
        inoremap <expr> <Tab>   pumvisible() ? "\<C-n>" : "\<Tab>"
        inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
        inoremap <expr> <cr>    pumvisible() ? asyncomplete#close_popup() : "\<cr>"
        " inoremap <expr> <cr> pumvisible() ? asyncomplete#close_popup() . "\<cr>" : "\<cr>"
        imap <c-space> <Plug>(asyncomplete_force_refresh)
        " For Vim 8 (<c-@> corresponds to <c-space>):
        " imap <c-@> <Plug>(asyncomplete_force_refresh)
        let g:asyncomplete_auto_completeopt = 1
        " allow modifying the completeopt variable, or it will be overridden all the time
        " let g:asyncomplete_auto_completeopt = 0
        " set completeopt=menuone,noinsert,noselect,preview

        " To auto close preview window when completion is done. 
        autocmd! CompleteDone * if pumvisible() == 0 | pclose | endif
        call s:asyncomplete_file()
        call s:asyncomplete_lsp()
    endif
endfunction

function! s:asyncomplete_ale() abort
    " Plug prefix .. 'andreypopp/asyncomplete-ale.vim'
    try
        packadd asyncomplete-ale.vim
        au User asyncomplete_setup call asyncomplete#register_source(asyncomplete#sources#file#get_source_options({
                    \ 'name': 'ale',
                    \ 'allowlist': ['*'],
                    \ 'priority': 10,
                    \ 'completor': function('asyncomplete#sources#ale#completor')
                    \ }))
    catch /.*/
        echoerr v:exception
    endtry
endfunction

function! s:asyncomplete_ultisips() abort
    " Plug prefix .. 'prabirshrestha/asyncomplete-ultisnips.vim'
    try
        packadd asyncomplete-ultisnips.vim
        au User asyncomplete_setup call asyncomplete#register_source(asyncomplete#sources#file#get_source_options({
                    \ 'name': 'ultisnips',
                    \ 'allowlist': ['*'],
                    \ 'priority': 10,
                    \ 'completor': function('asyncomplete#sources#ultisnips#completor')
                    \ }))
    catch /.*/
        echoerr v:exception
    endtry
endfunction

function! s:asyncomplete_tags() abort
    " Plug prefix .. 'prabirshrestha/asyncomplete-tags.vim'
    try
        packadd asyncomplete-tags.vim
        au User asyncomplete_setup call asyncomplete#register_source(asyncomplete#sources#file#get_source_options({
                    \ 'name': 'tags',
                    \ 'allowlist': ['*'],
                    \ 'priority': 10,
                    \ 'completor': function('asyncomplete#sources#tags#completor')
                    \ }))
    catch /.*/
        echoerr v:exception
    endtry
endfunction

function! s:asyncomplete_file() abort
    try
        packadd asyncomplete-file.vim
        au User asyncomplete_setup call asyncomplete#register_source(asyncomplete#sources#file#get_source_options({
                    \ 'name': 'file',
                    \ 'allowlist': ['*'],
                    \ 'priority': 10,
                    \ 'completor': function('asyncomplete#sources#file#completor')
                    \ }))
    catch /.*/
        echoerr v:exception
    endtry
endfunction

function! s:asyncomplete_lsp() abort
    if !exists('g:asyncomplete_lsp_loaded')
        try
            packadd asyncomplete-lsp.vim
        catch /.*/
            echoerr v:exception
        endtry
    endif
    if exists('g:asyncomplete_lsp_loaded') && g:asyncomplete_lsp_loaded
        " Plug 'prabirshrestha/asyncomplete.vim'
        " Plug 'prabirshrestha/vim-lsp'
        " Plug 'prabirshrestha/asyncomplete-lsp.vim'
        if executable('pyls')
            " pip install python-language-server
            au User lsp_setup call lsp#register_server({
                        \ 'name': 'pyls',
                        \ 'cmd': {server_info->['pyls']},
                        \ 'allowlist': ['python'],
                        \ })
        endif
    endif
endfunction
